<?php

namespace tmcore\services\crud\generators;

use tmcore\services\crud\enum\CrudEnum;
use tmcore\services\crud\UtilService;
use think\App;

abstract class Generate
{
    /**
     * @var App
     */
    protected App $app;

    /**
     * 应用目录
     * @var string
     */
    protected string $basePath;

    /**
     * 系统根目录
     * @var string
     */
    protected string $rootPath;

    /**
     * 文件类型
     * @var string
     */
    protected string $fileType = '';

    /**
     * 模板文件夹
     * @var string
     */
    protected string $templateDir;

    /**
     * 模块名
     * @var string
     */
    protected string $moduleName;

    /**
     * 类目录
     * @var string
     */
    protected string $classDir;

    /**
     * 生成的文件夹目录
     * @var string
     */
    protected string $crudDir;

    /**
     * 表信息
     * @var array
     */
    protected array $crudData;

    /**
     * 表字段信息
     * @var array
     */
    protected array $crudColumn;

    /**
     * 数据库获取器后缀
     * @var string
     */
    protected string $attrPrefix = 'Desc';

    /**
     * 文件内容
     * @var string
     */
    protected string $content;

    /**
     * 参数
     * @var array
     */
    protected array $params = [];

    /**
     * 菜单配置
     * @var array
     */
    protected array $menuConfig;

    /**
     * 删除配置
     * @var array
     */
    protected array $deleteConfig;

    /**
     * 树表配置
     * @var array
     */
    protected array $treeConfig;

    /**
     * 关联配置
     * @var array
     */
    protected array $joinConfig;

    /**
     * 生成到模块的文件路径
     * @var string
     */
    protected string $crudModuleFilePath;

    /**
     * 生成到data目录的文件路径
     * @var string
     */
    protected string $crudDataFilePath;

    /**
     * 生成文件名称
     * @var string
     */
    protected string $crudFileName;

    /**
     * 初始化
     * @param App $app
     */
    public function __construct(App $app)
    {
        $this->setBaseInfo();
        $this->setDefaultValue();
        $this->app = $app;
    }

    /**
     * 初始化信息
     */
    protected function setBaseInfo() {
        $this->basePath = base_path();
        $this->rootPath = root_path();
        $this->templateDir = $this->rootPath . 'tmcore/services/crud/tpl/';
        $this->crudDir = $this->rootPath . 'data/crud/';
        UtilService::checkDir($this->crudDir);
    }

    /**
     * 设置默认信息
     */
    protected function setDefaultValue()
    {
        $this->params['time'] = time();
        $this->params['crud_column_check'] = [];
    }

    /**
     * 初始化表数据
     * @param array $data
     * @return Generate
     */
    public function initData(array $data)
    {
        // 表信息
        $this->crudData = empty($data) ? []: $data;
        // 表字段信息
        $this->crudColumn = $data['table_column'] ?? [];
        // 模块名称
        $this->moduleName = !empty($data['module_name']) ? strtolower($data['module_name']) : 'admin';
        // 类目录名称
        $this->classDir = $data['class_folder'] ?? '';
        // 菜单配置
        $this->menuConfig = [
            'pid' => $data['menu']['pid'] ?? 0,
            'type' => $data['menu']['type'] ?? CrudEnum::MENU_MT,
            'name' => $data['menu']['name'] ?? $data['table_comment']
        ];
        // 删除配置
        $this->deleteConfig = [
            'type' => $data['delete']['type'] ?? CrudEnum::DELETE_TRUE,
            'name' => $data['delete']['name'] ?? CrudEnum::DELETE_NAME,
        ];
        // 树表配置
        $this->treeConfig = [
            'tree_id' => $data['tree']['id'] ?? '',
            'tree_pid' => $data['tree']['pid'] ?? '',
            'tree_name' => $data['tree']['name'] ?? '',
        ];
        // 关联配置
        $this->joinConfig = $data['join'] ?: [];
        // 设置参数
        $this->params['crud_column_check'] = $this->checkTableColumnType();

        // 设置文件路径
        $this->setFilePath();

        // 替换模板变量
        $this->replaceContent();

        return $this;
    }

    /**
     * 替换模板变量
     * @return mixed
     */
    abstract public function replaceContent();

    /**
     * 获取模板
     * @param string $type
     * @return mixed
     */
    abstract public function getStub(string $type = '');

    /**
     * 设置文件路径
     * @return mixed
     */
    abstract public function setFilePath();

    /**
     * 生成文件
     */
    public function generate()
    {
        //生成方式: 1-压缩包下载 2-生成到模块
        if ($this->crudData['crud_type'] == 2) {
            $path = $this->crudModuleFilePath;
        } else {
            $path = $this->crudDataFilePath;
        }
        // 写入内容
        file_put_contents($path, $this->content);
    }

    /**
     * 获取拼接的模版
     * @param array $tpl_arr
     * @param bool $is_wrap
     * @return string
     */
    public function getStubContent(array $tpl_arr, $is_wrap = true)
    {
        $content = '';
        foreach ($tpl_arr as $item) {
            $content .= file_get_contents($this->getStub($item)) . PHP_EOL . ($is_wrap? PHP_EOL : '');
        }
        return $content;
    }

    /**
     * 文件信息
     * @return array
     */
    public function getFileInfo(): array
    {
        return [
            'name' => $this->crudFileName,
            'type' => $this->fileType,
            'content' => $this->content
        ];
    }

    /**
     * 设置生成文件内容
     * @param string $content
     * @return Generate
     */
    public function setContent(string $content)
    {
        $this->content = $content;
        return $this;
    }

    /**
     * 获取文件内容
     * @return string
     */
    public function getContent()
    {
        return $this->content;
    }

    /**
     * 设置生成文件名称
     * @param string $name
     * @return $this
     */
    public function setCrudFileName(string $name)
    {
        $this->crudFileName = $name;
        return $this;
    }

    /**
     * 设置生成到模块的文件路径
     * @param string $path
     * @return Generate
     */
    public function setCrudModuleFilePath(string $path)
    {
        $this->crudModuleFilePath = $path . $this->crudFileName;
        UtilService::checkDir($path);
        return $this;
    }

    /**
     * 设置生成到data目录的文件路径
     * @param string $path
     * @return Generate
     */
    public function setCrudDataFilePath(string $path)
    {
        $this->crudDataFilePath = $path . $this->crudFileName;
        UtilService::checkDir($path);
        return $this;
    }

    /**
     * 获取模板路径
     * @param string $tpl
     * @return string
     */
    public function getTplPath(string $tpl): string
    {
        return $this->templateDir . $tpl . '.stub';
    }

    /**
     * 获取表名
     * @return string|string[]
     */
    public function getTableName()
    {
        return UtilService::get_no_prefix_table_name($this->crudData['table_name']);
    }

    /**
     * 获取驼峰类名(首字母大写)
     * @return string|string[]
     */
    public function getCamelClassName()
    {
        return UtilService::studly($this->crudData['class_name']);
    }

    /**
     * 获取驼峰表名(首字母大写)
     * @return string
     */
    public function getCamelTableName()
    {
        return UtilService::studly($this->getTableName());
    }

    /**
     * 表名小写
     * @return string
     */
    public function getLowerTableName()
    {
        return UtilService::lower($this->getTableName());
    }

    /**
     * 获取table字段描述
     * @param $column
     * @return string
     */
    public function getTableColumnComment($column)
    {
        if(strpos($column, ':') !== false) {
            return explode(':', $column)[0];
        } else {
            return $column;
        }
    }

    /**
     * 判断字段类型数据
     * @return array
     */
    private function checkTableColumnType() {
        $is_dict = false;
        $is_extra = false;
        $is_userSelect = false;
        $is_areaSelect = false;
        $is_edit_datePicker = false;
        $is_detail_datePicker = false;
        $is_index_datePicker = false;
        $is_detail_imageSelect = false;
        $is_index_imageSelect = false;
        $append_fields = [];
        if($this->crudColumn) {
            foreach ($this->crudColumn as $value) {
                if($value['dict_type']) $is_dict = true;
                if(!empty($value['extra']['list'])) $is_extra = true;
                if($value['view_type'] == 'userSelect') $is_userSelect = true;
                if($value['view_type'] == 'areaSelect') $is_areaSelect = true;
                if(!$value['is_pk'] && ($value['is_update'] || $value['is_insert']) && ($value['view_type'] == 'datePicker' || $value['view_type'] == 'timePicker')) $is_edit_datePicker = true;
                if(!$value['is_pk'] && $value['is_list'] && ($value['view_type'] == 'datePicker' || $value['view_type'] == 'timePicker')) $is_index_datePicker = true;
                if(!$value['is_pk'] && $value['is_detail'] && ($value['view_type'] == 'datePicker' || $value['view_type'] == 'timePicker')) $is_detail_datePicker = true;
                if(!$value['is_pk'] && $value['is_list'] && ($value['view_type'] == 'userSelect' || $value['view_type'] == 'imageSelect' || $value['view_type'] == 'videoSelect' || $value['view_type'] == 'fileSelect' || $this->crudData['is_import'])) $is_index_imageSelect = true;
                if(!$value['is_pk'] && $value['is_detail'] && ($value['view_type'] == 'userSelect' || $value['view_type'] == 'imageSelect' || $value['view_type'] == 'videoSelect' || $value['view_type'] == 'fileSelect' || $this->crudData['is_import'])) $is_detail_imageSelect = true;
                if(!$value['is_pk'] && ($value['dict_type'] || !empty($value['extra']['list']) || $value['view_type'] == 'userSelect' || $value['view_type'] == 'areaSelect')) {
                    array_push($append_fields, $value['column_name']);
                }
            }
        }
        return [
            'is_dict' => $is_dict,
            'is_extra' => $is_extra,
            'is_userSelect' => $is_userSelect,
            'is_areaSelect' => $is_areaSelect,
            'is_edit_datePicker' => $is_edit_datePicker,
            'is_detail_datePicker' => $is_detail_datePicker,
            'is_index_datePicker' => $is_index_datePicker,
            'is_detail_imageSelect' => $is_detail_imageSelect,
            'is_index_imageSelect' => $is_index_imageSelect,
            'append_fields' => $append_fields
        ];
    }

    /**
     * 获取表主键
     * @return mixed|string
     */
    public function getPk()
    {
        return UtilService::getPk($this->crudColumn);
    }

    /**
     * 获取作者信息
     * @return mixed|string
     */
    public function getAuthorContent()
    {
        return empty($this->crudData['author']) ? 'tmadmin' : $this->crudData['author'];
    }

    /**
     * 是否为压缩包生成
     * @return bool
     */
    public function isTypeZip()
    {
        return $this->crudData['crud_type'] == CrudEnum::CRUD_TYPE_ZIP;
    }

    /**
     * 是否为树表
     * @return bool
     */
    public function isTypeTree()
    {
        return $this->crudData['tpl_type'] == CrudEnum::TPL_TYPE_TREE;
    }

}